package com.palm.easy.service;

import com.jfinal.template.Engine;
import com.jfinal.template.Template;
import com.palm.easy.ManagerConfiguration;
import com.palm.easy.domain.Service;
import com.palm.easy.domain.ServiceItem;
import com.palm.easy.util.StringUtil;
import org.noear.solon.Utils;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Init;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.handle.Result;

import java.io.*;
import java.util.*;

/**
 * 代理Nginx
 */
@Component
public class NginxService {

    @Inject
    private ConfigService configService;
    //    @Inject
//    private ServicesService servicesService;
    @Inject
    private ServerManageService serverManageService;
    private String path = "/usr/local/openresty/bin/openresty";
    private String workPath;
    private Engine engine;
    private boolean running;

    @Init
    public void init() {
        this.engine = Engine.create("nginx_config");
        this.engine.setDevMode(true);
        this.running = checkRunning();
        File nginxWorkDir = new File(ManagerConfiguration.localPath(), "nginx");
        if (!nginxWorkDir.exists()) {
            nginxWorkDir.mkdirs();
            try (InputStream tpl = NginxService.class.getResourceAsStream("/conf/nginx.conf.tpl")) {
                Utils.transferTo(tpl, new FileOutputStream(new File(nginxWorkDir, "nginx.conf.tpl")));
            } catch (IOException e) {
                e.printStackTrace();
            }
            try (InputStream mime = NginxService.class.getResourceAsStream("/conf/mime.types")) {
                Utils.transferTo(mime, new FileOutputStream(new File(nginxWorkDir, "mime.types")));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        this.workPath = nginxWorkDir.getAbsolutePath();
        String path = configService.getConfig("nginx");
        if (StringUtil.isNotEmpty(path)) {
            this.path = path;
        }
    }

    public boolean status() {
        return running;
    }

    public String getPath() {
        return path;
    }

    /**
     * 检查是否在运行
     *
     * @return
     */
    private boolean checkRunning() {
        if (StringUtil.isEmpty(path)) {
            return false;
        }
        String configFilePath = new File(workPath + "/nginx.conf").getAbsolutePath();
        String osName = System.getProperty("os.name").toLowerCase();
        if (osName.indexOf("windows") > -1) {
            try {
                execute("tasklist");
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            try {
                String s = execute("ps -A");
                String ps[] = s.split("\n");
                for (String p : ps) {
                    // System.out.println(p.trim());
                    String pt = p.trim();
                    if (pt.endsWith(configFilePath)||pt.indexOf(path)>-1) {
                        return true;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    public Result stop() {
        if (StringUtil.isEmpty(path)) {
            return Result.failure("没有设置Openresty路径");
        }
        File openresty = new File(path);
        if (!openresty.exists()) {
            return Result.failure("没有找到Openresty");
        }
        try {
            String r = execute(openresty.getAbsolutePath() + " -s stop");
            if (StringUtil.isEmpty(r)) {
                running = false;
                return Result.succeed("服务已停止");
            } else {
                return Result.failure(r);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Result.failure();
    }

    public Result reload() {
        if (StringUtil.isEmpty(path)) {
            return Result.failure("没有设置Openresty路径");
        }
        File openresty = new File(path);
        if (!openresty.exists()) {
            return Result.failure("没有找到Openresty");
        }
        if (!running) {
            return Result.failure("Openresty 未运行");
        }
        File dir = new File(workPath);
        //执行模板生成配置
        renderConfig();
        String result = null;
        try {
            result = execute(openresty.getAbsolutePath() + " -t -c " + new File(workPath + "/nginx.conf").getAbsolutePath());
            if (!result.endsWith("test is successful")) {
                return Result.failure(result);
            }
            result = execute(openresty.getAbsolutePath() + " -s reload");
            if (!StringUtil.isEmpty(result)) {
                return Result.failure(result);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        running = true;
        return Result.succeed("配置已重新载入");
    }

    public Result start(boolean restart) {
        if (StringUtil.isEmpty(path)) {
            return Result.failure("没有设置Openresty路径");
        }
        File openresty = new File(path);
        if (!openresty.exists()) {
            return Result.failure("没有找到Openresty");
        }
        if (running) {
            return Result.failure("Openresty 运行中");
        }
        //执行模板生成配置
        renderConfig();
        try {
            //test
            String result = execute(openresty.getAbsolutePath() + " -t -c " + new File(workPath + "/nginx.conf").getAbsolutePath());
            if (!result.endsWith("test is successful")) {
                return Result.failure(result);
            }
            String r = execute(openresty.getAbsolutePath() + " -c " + new File(workPath + "/nginx.conf").getAbsolutePath());
            if (!StringUtil.isEmpty(r)) {
                return Result.failure(r);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        running = true;
        return Result.succeed("服务已启动");
    }

    public String getConfigTemplate() {
        File file = new File(workPath + "/nginx.conf.tpl");
        if (file.exists()) {
            return StringUtil.readFrom(file);
        } else {
            return "";
        }
    }

    private void saveTemplate(String template) {
        File file = new File(workPath + "/nginx.conf.tpl");
        StringUtil.write(file, template);
        renderConfig();
    }

    public void saveNginxCfg(String path, String configTpl) {
        configService.saveConfig("nginx", path);
        this.path = path;
        saveTemplate(configTpl);
//        File file=new File(workPath+"/nginx.conf.tpl");
//        StringUtil.write(file,configTpl);
    }

    private void renderConfig() {
        engine.setBaseTemplatePath(new File(workPath).getAbsolutePath());
        Template template = engine.getTemplate("nginx.conf.tpl");
        Map<String, Object> params = new HashMap<>();
        params.put("root", new File(new File(workPath).getParent(), "web").getAbsolutePath());
        params.put("processes", Runtime.getRuntime().availableProcessors());
        params.put("configPath", new File(workPath).getAbsolutePath());
        Collection<ServiceItem> services = serverManageService.serviceItemList();
        params.put("services", services);
        String data = template.renderToString(params);
        StringUtil.write(new File(workPath + "/nginx.conf"), data);
    }

    private static String execute(String command) throws IOException {
        Runtime runtime = Runtime.getRuntime();
        Process process = runtime.exec(command);
        BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
        String line = null;

        List<String> bd = new ArrayList<>();
        while ((line = br.readLine()) != null) {
            // build.append(line);
            bd.add(line);
        }
        if (line == null) {
            br = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
            while ((line = br.readLine()) != null) {
                bd.add(line);
            }
        }
        return String.join("\n", bd);
    }

    /**
     * 预览配置
     *
     * @return
     */
    public Result previewCfg() {
        File file = new File(workPath + "/nginx.conf");
        return Result.succeed(StringUtil.readFrom(file));
    }

}
